It has become commonplace for a wide variety of application routines to be written for multi-threaded execution. This arises from the incorporation of processor components capable of supporting multi-threaded execution into an increasing variety of computing devices. However, while multi-threaded execution provides numerous advantages, the work of writing portions of an application routine to execute concurrently on different threads in a coordinated manner presents challenges. Mistakes resulting in uncoordinated accesses (e.g., read and write operations, or pairs of write operations) by different portions of an application routine to the same data are not uncommon, and can beget unexpected behavior that can be difficult to trace to the mistakes that were made in writing in the application routine.
Of particular concern are instances of one portion of an application routine that reads data close enough in time to when another portion of the application routine writes that same data that it is not reliably predictable which of the read and write operations will occur before the other. Thus, the read operation may retrieve the data either before or after it is modified by the write operation. Also of particular concern are instances in which the same data is twice written to in a pair of uncoordinated write operations such that the state of that data it is not reliably predictable after those two write operations. In other words, a lack of coordination between two accesses to the same data leads to an insufficiently coordinated result.
Various techniques have been devised to trace, step-by-step, the execution of each such portion of an application routine on their separate threads, including executing a debugging routine alongside those different portions to monitor various break points inserted among the instructions of those portions and/or to monitor their data accesses. However, such debugging routines typically consume considerable processing and/or storage resources, themselves. Indeed, the fact of the execution of such a debugging routine alongside an application routine may consume enough resources to alter the behavior of the application routine such that the uncoordinated accesses that are sought to be traced for debugging simply never occur. Further, in situations where the processing and/or storage resources provided by a computing device are closely matched to the resources required by an application routine, there may be insufficient resources available to accommodate the execution of both the application routine and such a debugging routine.